08. 강한 결합: 복잡하게 얽혀서 풀 수 없는 구조

📌 Contents

  • 결합도란 '모듈 사이의 의존도를 나타내는 지표'
  • 모듈을 클래스라 생각하면, '클래스 사이의 의존도를 나타내는 지표'를 결합도라 할 수 있음
  • 결합도가 높으면 강한 결합, 낮으면 느슨한 결합
  • 느슨한 결합 구조로 개선하면 코드 변경이 쉬워짐
  • 책무를 제대로 생각하지 않으면, 결합도가 높아지기 쉬움
  • 사전적으로 '책무'란 '책임과 의무, 즉 의무를 다 해야 하는 책임'
  • 소프트웨어 설계에서 '책무'란 '어떤 관심사를 정상적으로 작동하게 제어해야 하는 책임'

📌 결합도와 책무

  • 할인 서비스의 예시로 결합도와 책무를 설명


  • 온라인 쇼핑몰에 할인 서비스가 추가 되어 일반 할인을 담당하는 클래스가 있음 (DiscountManger)
    • 올바른 상품인지 확인
    • getDiscountPrice로 할인 가격을 계산
    • productDiscount.canDiscount를 확인하여 할인 가능한 경우에는 할인 가격을 모두 더하고, 할인이 불가능한 경우에는 원래 상품 가격을 모두 더함
    • 가격 총합이 상한가인 200,000원 이내인 경우, 상품 리스트에 추가
  • 이후에 여름 할인 사양이 추가되어 여름 할인을 담당하는 클래스를 만듬 (summerDiscountManger)
    • 올바른 상품인지 확인
    • 할인 금액이 일반 할인과 마찬가지로 3000원 까지이므로, getDiscountPrice로 할인 가격을 계산
    • productDiscount.canDiscount를 확인하여 할인 가능한 경우에는 할인 가격을 모두 더하고, 할인이 불가능한 경우에는 원래 상품 가격을 모두 더함
    • 가격 총합이 상한가인 300,000원 이내인 경우, 상품 리스트에 추가


  • 두 클래스의 구현 담당자는 다름

다양한 버그

  • 일반 할인 가격을 4,000원으로 변경 시 DiscountManger 구현 담당자가 getDiscountPrice를 변경함
  • 이 때 summerDiscountManger에서도 3,000원 할인이 4,000원 할인으로 변경됨
  • 일반 할인 가격만 높히려 했는데 여름 할인 가격도 같이 높아지는 버그가 발생함


  • DiscountManger에서는 가격이 음수인지 판단하는 유효성 검사가 있는데 summerDiscountManger에는 유효성 검사를 하지 못해 음수도 들어갈 수 있는 버그 발생


  • productDiscount.canDiscount가 일반 할인 가능 여부여서 여름 할인 가능 여부를 product.canDiscount로 추가하게 되면 두 개 이름이 비슷해 잘못 활용해 버그가 발생할 수 있음

로직의 위치에 일관성이 없음

  • DiscountManger 클래스와 summerDiscountManger 클래스가 상품 정보 확인 말고도 할인 가격 계산, 할인 적용 여부 판단, 총액 상환 확인 등 너무 많은 일을 함
  • Product가 직접 해야할 유효성 검사도 함
  • ProductDiscound.canDiscount와 Product.canDiscount의 이름이 유사해 어떤 것이 일반 할인이고 여름 할인인지 구분 힘듬
  • 여름 할인 가격 계산을 위해 summerDiscountManger가 DiscountManger의 일반 할인 로직을 활용


  • 어떤 클래스는 처리해야 할 작업이 집중되어 있고, 어떤 클래스는 특별히 하는 일이 없음
  • 어떤 클래스는 편의를 위해 다른 클래스의 메서드를 무리하게 활용
  • 이런 클래스 설계가 바로 책무를 고려하지 않은 설계라고 할 수 있음

단일 책임 원칙

  • 소프트웨어의 책임이란 '자신의 관심사와 관련해서, 정상적으로 동작하도록 제어하는 것'
  • 이 때 중요한 것이 바로 단일 책임 원칙
  • 단일 책임 원칙은 '클래스가 담당하는 책임은 하나로 제한해야 한다'는 설계 원칙
  • 이 원칙의 관점에서 앞서 설명했던 할인 서비스의 클래스를 살펴보면, 수많은 악마가 보일 것임

단일 책임 원칙 위반으로 발생하는 악마

  • DiscountManager.getDiscountPrice는 일반 할인 가격 계산을 책임지는 메서드임. 여름 할인을 책임지기 위한 것이 아님
  • 상품명과 가격이 타당한지 판단하는 책임은 DiscountManager나 SummerDiscountManager가 아닌 Product 클래스가 가져야할 책임임
  • Product 클래스는 아무것도 하지 않는 미성숙한 클래스가 됨
  • DiscountManager는 다른 클래스에게 책임을 지우지 않고 무엇이든 대신 해 주는, 과보호하는 부모임
  • 이렇게 책임을 대신 지는 클래스가 만들어지면, 다른 클래스가 제대로 성장할 수 없음(성숙해지지 않음)

책임이 하나가 되게 클래스 설계하기

  • 상품의 가격을 나타내는 RegularPrice 클래스를 만들어 잘못된 값이 들어오지 않게 유효성 검사 과정을 추가
  • 가격과 관련된 책임을 지는 클래스
  • 유효성 검사와 관련된 책임을 RegularPrice가 지므로, 다른 곳에서 유효성 검사와 관련된 코드가 중복될 일이 없음
  • 일반 할인 가격, 여름 할인 가격과 관련된 내용을 개별적으로 책임지는 클래스 RegularDiscountPrice, SummerDiscountPrice를 만들어 값 객체로 설계하기
  • 클래스가 일반 할인 가격, 여름 할인 가격으로 구분되어 있어, 할인과 관련된 사양이 변경되어도 서로 영향을 주지 않음
  • 이와 같이 관심사에 따라 분리해서 독립되어 있는 구조를 느슨한 결합이라고 부름

Dry 원칙의 잘못된 적용

  • RegularDiscountPrice, SummerDiscountPrice 클래스의 로직은 대부분 같음. 할인 가격의 차이만 있음
  • 이를 보고 중복 코드라 생각해 중복을 제거하면 아까처럼 어떤 할인 가격 변경이 다른 것에 영향을 줌
  • 책무를 생각하지 않고 중복을 제거하면, 하나로 모인 로직이 여러 책무를 담당해야 함
  • DRY(Don't Repaet Yourself) 원칙이라는 것이 있음
  • '반복을 피해라'라는 의미인데, 이를 '코드 중복을 절대 허용하지 말라'로 받아들이는 사람들이 있음
  • 하지만 DRY는 각각의 개념 단위 내에서 반복을 하지 말라는 의미
  • 같은 로직, 비슷한 로직이라도 개념이 다르면 중복을 허용해야 함
  • 개념적으로 다른 것 까지도 무리하게 중복을 제거하려 하면, 강한 결합 상태가 되어, 단일 책임 원칙이 깨짐

Note

모든 지식은 시스템 내에서 단 한 번만, 애매하지 않고, 권위 있게 표현되어야 한다.
DRY원칙을 소개한 <<실용주의 프로그래머 20주년 기념판>>

📌 다양한 강한 결합 사례와 대처 방법

상속과 관련된 강한 결합

  • 상속은 주의해서 다루지 않으면, 곧바로 강한 결합 구조를 유발하는 위험한 문법임
슈퍼 클래스 의존
  • 상속 관계에서 서브 클래슨느 슈퍼 클래스에 굉장히 크게 의존함
  • 따라서 서브 클래스는 슈퍼 클래스의 구조를 하나하나 신경 써야 함
  • 슈퍼 클래스의 변화를 놓치는 순간, 버그가 만들어질 수 있음
  • 일반 적으로 슈퍼 클래스는 서브 클래스를 딱히 신경 쓰지 않고 변경하기 때문에, 서브 클래스에 문제가 발생하기 쉬움
상속보다 컴포지션
  • 슈퍼 클래스 의존으로 인한 강한 결합을 피하려면, 상속보다 컴포지션을 사용하는 것이 좋음
  • 컴포지션이란 사용하고 싶은 클래스를 private 인스턴스 변수로 갖고 사용하는 것을 의미

상속을 사용하는 나쁜 일반화

  • 상속을 사용하면 서브 클래스가 슈퍼 클래스의 로직을 그대로 사용하게 되므로, 슈퍼 클래스가 공통 로직을 두는 장소로 사용됨
  • 상속으로 무리하게 일반화하려고 하면 강한 결합이 발생하기 쉬움


  • 슈퍼 클래스를 두개의 서브 클래스로 상속해서 구현할 때 두 서브 클래스의 로직이 한 가지만 제외하고 같을 때 같은 부분을 슈퍼 클래스에 구현하고, 다른 부분만 따로 빼서 오버라이딩 해서 구현하려는 사람들이 있음
    • 예를 들어 일반 할인과 여름 할인을 구현할 때 두 개의 할인 방식이 같고 가격만 다르면, 슈퍼 클래스에서 할인 방식과 할인 가격을 나누게 될 수 있음
    • 그럼 일반 할인과 여름 할인 클래스에는 할인 가격을 리턴하는 메서드만 오버라이딩 하면 됨
    • 하지만 여름 할인의 할인 방식이 달라지게 되면, 여름 할인은 할인 방식에 대한 메서드를 오버라이딩하고 할인 가격에 대한 메서드와는 관련이 없어짐
  • 하나의 로직으로 봐야 하는 흐름이 두 클래스에 분산되어 있는 설계는 좋은 설계가 아님
  • 서브 클래스 중 일부와만 관련된 메서드가 등장하면 여러 가지 문제가 발생할 수 있음
  • 어디부터 어디까지가 관련 있는지 로직을 추적하기가 매우 어려워서, 디버깅과 요구 사항 변경이 매우 힘들어짐


  • 또한 슈퍼 클래스에서 서브 클래스의 로직을 구현하고, instanceof로 서브 클래스의 자료형을 판단해 구현하는 경우도 있음
    • 상속은 다른 동작을 구현하기 위해 사용하는 것임
    • 상속은 전략 패턴 등으로 조건 분기를 줄일 때 활용할 수 있음
    • 하지만 instanceof를 이용해서 구현한다면, 조건 분기를 줄이지 못함
    • 또한 비즈니스 개념이 분산됨


  • 상속은 잘만 설계하면 아무 문제 없음
  • 하지만 여러 악마를 불러들일 수 있기 때문에 신중히 사용해야함
  • 상속은 반드시 단일 책임 원칙을 염두해 두고 구현하도록 해야함
  • 그리고 값 객체와 컴포지션 등 다른 설계를 사용할 수 없는지 반드시 검토해 봐야함

인스턴스 변수별로 클래스 분할이 가능한 로직

  • 한 클래스에 책임이 다른 메서드들이 정의되어 있으면, 여러 문제가 발생할 수 있음
  • '각 메서드가 어떤 인스턴스 변수를 활용하고 있는가' 살펴보기
class Util {
  private int reservationId; // 상품 예약 ID
  private ViewSettings viewSettings; // 화면 표시 설정
  private MailMagazine mailMagazine; // 메일 매거진

  void cancelReservation() {
    // reservationId를 사용한 예약 취소 처리
  }

  void darkMode() {
    // viewSettings를 사용한 다크 모드 표시 전환 처리
  }

  void beginSendMail() {
    // mailMagazine을 사용한 메일 전송 처리
  }
}

class Reservation {
  private int reservationId; // 상품 예약 ID

   void cancel() {
    // reservationId를 사용한 예약 취소 처리
  }
}

class ViewCustomizing {
  private ViewSettings viewSettings; // 화면 표시 설정

  void darkMode() {
    // viewSettings를 사용한 다크 모드 표시 전환 처리
  }
}

class MailMagazineService {
  private MailMagazine mailMagazine; // 메일 매거진

  void beginSend() {
    // mailMagazine을 사용한 메일 전송 처리
  }
}
  • 클래스의 의존 관계가 단순하면 분리하기 쉽지만, 실제 제품 코드에서는 클래스 간 의존 관계가 복잡함
  • 클래스를 잘 분리하려면, 각각의 인스턴스 변수와 메서드가 무엇과 관련 있는지 잘 파악해야 함
  • 관계를 파악할 때는 의존 관계 그림(영향 스케치)을 활용해 보는 것이 좋음
  • 영향 스케치는 종이 위에 연필로 그리거나, 도형을 그릴 수 있는 애플리케이션을 활용해도 됨
  • 복잡한 소스 코드는 이러한 방법만으로는 영향 스케치를 그리기 힘드니, 소스 코드를 자동으로 분석해서 영향 스케치를 그려주는 Jig 같은 도구를 활용하는 것도 좋음

특별한 이유 없이 public 사용하지 않기

  • public과 private 같은 접근 수식자를 붙이면, 클래스와 메서드의 가시성을 제어할 수 있음
  • 특별한 이유 없이 public을 붙이면, 강한 결합 구조가 되어 버림
  • public으로 선언하면, 다른 패키지에서 접근할 수 있음
  • 이유 없이 public으로 만들면, 관계를 맺지 않았으면 하는 클래스끼리도 결합되어, 영향 범위가 확대됨 -> 강한 결합 구조가 됨
  • 강한 결합을 피하려면, 접근 수식자로 가시성을 적절하게 제어해야 함
    • public: 모든 클래스에서 접근 가능
    • protected: 같은 클래스와 서브 클래스에서 접근 가능
    • 없음: 같은 패키지에서만 접근 가능, package private이라고 부름
    • private: 같은 클래스에서만 접근 가능


  • 댜양한 프로그래밍 언어와 프레임워크에서 접근 수식자를 생략하도록 허용
  • 다른 접근 방식을 지정할 때만 접근 수식자를 명시하는 패턴
  • 왜 접근 수식자를 생략한 디폴트 상태가 package private일까?
    • 패키지들의 불필요한 의존 관계를 피할 때 적절하기 때문
    • 패키지는 밀접한 클래스끼리 응집하게 설계
    • 반면 패키지 바깥의 클래스와는 느슨하게 결합하도록 설계
    • 즉, 외부에서는 접근할 수 없게 하는 것. 그래서 package private이 적절함
    • 외부에 정말로 공개하고 싶은 클래스만 한정해서 public을 붙임


  • 실제로 부적절하다고 여겨지는 상황에서도 publicdl 많이 사용됨. 왜 그럴까?
  • 대부분 입문서나 입문자 대상 강의에서 public을 표준으로 사용하기 때문
  • 입문서는 기본적으로 초보자가 언어를 익히는 것을 우선시하므로, '설계 관점에서 바람직한가'를 고려하지 않는 경우가 있음
  • 입문서가 나쁜게 아니라 관점이 다른 것임
  • 따라서 초보자는 'public을 쓰는 것이 표준이구나'라고 생각이 들 수 있음
  • 클래스는 기본적으로 package private으로 만들고, 패키지 외부에 공개할 필요하 있는 클래스에 한해서만 public으로 선언

private 메서드가 너무 많다는 것은 책임이 너무 많다는 것

  • 다른 책임인 메서드를 가지고 있는 구조는 이상해질 수 있음
    • 주문 서비스 클래스에서 할인 가격 계산 메서드와 최근 본 상품 리스트를 확인하는 메서드를 가지고 있다면,
    • 예약 서비스 클래스에서 주문 서비스 클래스의 할인 가격 계산 메서드를 사용하는 이상한 의존 관계가 생길 수 있음
  • 이상한 의존 관계를 배제하고자, 다른 클래스에서 호출조차 할 수 없게 private 메서드로 구현할 수 있음
  • private 메서드가 너무 많이 쓰인 클래스는 하나가 아닌 너무 많은 책임을 갖고 있을 가능성이 높음
  • 여러 책임 로직이 private 메서드로 구현되어 있는 것임
  • 책임이 다른 메서드는 다른 클래스로 분리하는 것이 좋음
    • 할인 가격은 DiscountPrice 클래스, 최근 본 상품 리스트는 ProductBrowsingHistory 클래스로 분리하자

높은 응집도를 오해해서 생기는 강한 결합

  • 관련이 깊은 데이터와 논리를 한곳에 모은 구조를 응집도가 높은 구조라고 함
  • 높은 응집도를 잘못 이해해서 강한 결합이 발생하는 경우가 있음
  • 관련이 깊을거라 생각해 하나의 클래스에 모았지만, 다른 개념이 섞여 있어 강한 결합에 해당될 수 있음
  • 다른 개념과 관련된 로직이 섞이면, 어디에 어떤 로직이 구현되어 있는지 확인하기 힘듬
  • 응집도가 높다는 개념을 염두에 두고, 관련이 깊다고 생각되는 로직을 한곳에 모으려고 했지만, 결과적으로 강한 결합 구조를 만드는 상황은 매우 자주 일어남
  • 각각의 개념을 분리해야, 느슨한 결합 구조로 만들 수 있음. '결합이 느슨하고 응집도가 높은 설계'
  • 응집도를 높이는 설계를 할 때는 다른 개념이 섞여 들어와 강한 결합을 만드는게 아닌지 항상 주의해야함

스마트 UI

  • 화면 표시를 담당하는 클래스 중에서 화면 표시와 직접적인 관련이 없는 책무가 구현되어 있는 클래스를 스마트 UI라고 부름
  • 개발 초기 단계에는 서비스를 서둘러 런칭하기 위해, 복잡한 계산 로직을 프런트 쪽에 구현하기도 함
  • 나중에 화면 디자인을 다시 만들고 싶을 때, 기능은 같게 유지하면서, 디자인을 완전히 바꾸려하면 버그가 발생하기 쉬움
  • 스마트 UI는 화면 표시에 관한 책무와 그렇지 않은 책무가 강하게 결합되어 있기 때문에, 변경하기가 아주 힘듬
  • 이들은 서로 다른 클래스로 분할하는 것이 좋음 (책무를 분리하는 편리한 아키텍처로 MVVM 패턴이 있음)

거대 데이터 클래스

  • 1장에서 다루었던 데이터 클래스가 더욱 커지면, 거대 데이터 클래스가 됨
  • 각각의 유스케이스에서 필요한 데이터만 접근하고 사용할 수 있게 구성하는 것이 좋음
  • 하지만 거대 데이터 클래스는 다양한 데이터를 가지므로, 수많은 유스케이스에서 사용됨
  • 결국 전역 변수와 같은 성질을 띠게 됨
  • 동기화 하느라 성능이 저하되는 등 전역 변수와 동일한 유형의 다양한 폐해가 발생함

트랜잭션 스크립트 패턴

  • 메서드 내부의 일련의 처리가 하나하나 길게 작성되어 있는 구조를 트랜잭션 스크립트 패턴이라고 함 (절차적 프로그래밍이라고도 함)
  • '데이터를 보유하고 있는 클래스(데이터 클래스)'와 '데이터를 처리하는 클래스'를 나누어 구현할 때 자주 발생하는 형태
  • 이를 남용하면 메서드 하나가 길게는 수백 줄의 거대한 로직을 갖게 됨
  • 그러면 응집도는 낮아지고 결합은 강해지므로 변경하기 매우 어려워짐

갓 클래스

  • 트랜잭션 스크립트 패턴에서 한 단계 더 나아가면, 갓 클래스가 됨
  • 갓 클래스는 하나의 클래스 내부에 수천에서 수만 줄의 로직을 담고 있으며, 수많은 책임을 담당하는 로직이 난잡하게 섞여 있는 클래스임 (진흙 덩어리라고도 부름)
  • 어떤 로직과 관련이 있는지, 책무를 파악하기가 굉장히 힘듬
  • 기능을 수정하려면, 영향 범위를 파악하기 위해 수천 수만 줄의 로직을 읽어야 함
  • 영향 범위 확인 시 놓치는 부분이 생기기 쉬우므로, 버그가 스며들기도 쉬움
  • 개발이라는 과정이 버그를 수정하고, 또 누락된 부분을 다시 수정하는 과정을 반복하는 단순 노동으로 변질됨. 두더지 잡기 게임 같음
  • 갓 클래스는 잘못된 값을 검출하는 로직조차 난잡하게 작성되어 있는 경우가 많으며, 최악의 상황에는 아예 작성되어 있지 않은 경우도 있음
  • 잘못된 값 때문에 문제가 생겨도 대체 무엇이 원인인지 추적하기 힘들고, 많은 시간이 걸림

강한 결합 클래스 대처 방법

  • 거대 데이터 클래스, 트랜잭션 스크립트 패턴, 갓 클래스처럼 강한 결합 클래스에 대처하는 방법은 모두 같음
  • 객체 지향 설계와 단일 책임 원칙에 따라 제대로 설계하면 됨
  • 거대한 강한 결합 클래스는 책임별로 클래스를 분할해야 함
  • 프로그래밍 언어마다 조금씩 다를 수 있지만, 단일 책임 원칙에 따라 설계된 클래스는 아무리 많아도 200줄 정도, 일반적으로는 100줄 정도임
  • 조기 리턴(6장), 전략 패턴(6장), 일급 컬렉션(7장) 등 다양한 방법을 활용해 볼 수 있음
  • 목적 중심 이름 설계(10장) 방법도 큰 도움이 됨

❓ Questions

❓ DRY 원칙의 잘못된 적용

  • 예전에 뉴스스탠드를 개발한적이 있는데, 이 때 구독 리스트 보기와 그냥 리스트 보기의 형태가 비슷해 공통 컴포넌트로 만드려고 한 적이 있었음
  • 근데 완전 형태가 같은게 아니라 조금 다른 부분이 있어서, if문 조건 분기로 구독일 때, 그냥일 때 나눠서 하려고 한적이 있었음
  • 이러한 방식이 Dry 원칙의 잘못된 적용의 예시인거 같음
  • 구독 리스트 보기와 그냥 리스트 보기의 개념은 다른 것이기 때문에 형태가 비슷해도 공통으로 만들어 중복을 제거하는 것은 바람직 하지 않았음 - 조건 분기를 하는 순간부터 일반 로직이 아니게 되므로, 일반화 해서는 안됨
  • 앞으로도 프론트 개발에서 공통 컴포넌트를 만들 때 이러한 부분을 잘 생각해서 만들면 좋을것 같다

❓ Java의 패키지?

  • Java의 패키지에 대해 클래스를 모아둔 것 정도의 느낌만 알고 제대로 알지 못했음
  • 파일 개념과 좀 헷갈렸었음. 자바를 따로 공부하지 않기 때문에 제대로 찾아본 적이 없음
  • 책을 읽으면서 패키지에 대해 궁금한 것들이 좀 생겼고, 패키지가 정확히 무엇인지 알아보고 싶어졌음
  • 클래스를 어떻게 패키지에 포함시키나?
  • 모든 클래스는 패키지에 속하나?
  • 한 파일에 있는 클래스는 모두 같은 패키지인가?
  • 다른 패키지의 클래스를 쓰고 싶을 때 어떤 식으로 사용하나?
    • public? import?
  • 같은 패키지면 다른 파일에 있어도 별다른 처리 없이 그냥 클래스를 사용할 수 있나?


  • 일단 모든 클래스는 패키지에 속해야 하는 것 같다.
  • 파일의 맨 위에 package로 선언을 해서 패키지에 포함 시킬 수 있고, package 선언을 안하면 기본 패키지에 들어간다고 한다.
  • 기본 패키지에 있으면 다른 패키지에서 사용 불가능 하다.
  • 자바의 소스 파일 하나에는 단 하나의 패키지 선언만 가능하기 때문에, 해당 파일에 있는 클래스는 모두 같은 패키지에 속한다.
  • 다른 패키지의 클래스를 쓰고 싶다면, 그 패키지를 import 해서 써야한다.
  • 이 때 public으로 선언된 클래스만 사용 가능하다.
  • public으로 선언 했다해서 다른 패키지에서 사용 가능한 것이 아니라, import를 통해 다른 패키지에 접근을 하는 것이고, 이때 public으로 선언된 클래스만 사용 가능한 것이였다.
  • 다른 파일이여도 같은 패키지라면, 별도의 import 없이 그냥 클래스를 가져다 쓸 수 있다고 한다.

❓ 강한 결합과 많은 책임

  • 책에서 맨 앞에서 '클래스 사이의 의존도를 나타내는 지표'인 결합도가 높으면 강한 결합이라고 한다.
  • 근데 책에서 한 클래스가 지는 책임이 많은 것도 강한 결합이라고 한다.
  • 클래스 하나가 모든 일은 하고 다른 클래스와 연관이 없으면 그건 강한 결합이라고 할 수 있나?
  • 책임을 많이 지게 되면 클래스 사이의 의존도가 높아질 수 는 있지만, 무조건 높아진다고 할 수 있나?
  • 결합도가 높은 것도 강한 결합인데 하나의 클래스가 많은 책임을 지는 것 즉, 한 클래스에 로직이 많이 들어있는 것도 강한 결합인가?


  • 스마트 UI를 보면 화면 표시 책무와 아닌 책무가 강하게 결합 되어서 강한 결합이라고 하는 것을 보면 책무들 즉, 메서드들끼리 강하게 연결되있어도 일단 강한 결합이 맞는 것 같다.
  • 데이터를 처리하는 모델과 화면을 표시하는 뷰가 강하게 결합되지 않고 느슨하게 결합되야 한다고 배웠는데, 이 때 두 로직을 하나로 합쳐버리면 그 것도 강하게 결합된 것이라고 알고 있었다.
  • 근데 하나의 클래스가 많은 책임을 갖고 그 책임들끼리 강하게 연결되어 있지 않으면, 그건 강한 결합인가?
  • 물론 하나의 클래스가 다른 클래스의 책임도 갖게되어 많은 책임을 지게되면 그 메서드를 가져다 쓰는 클래스들이 많아져서 결합도가 높아질 수 있고, 그것을 자신의 책임만 다하게 나눈다면, 그 나눠진 것들은 서로 영향을 안줄테니 책임을 줄이는 것이 느슨한 연결을 하게 하는 것일 수는 있지다.
  • 하지만 무조건 하나의 클래스가 많은 책임을 갖는데 그 책임이 자신과 관련된 것이고 그것을 다른 클래스에서 사용하지 않는다면, 강한 결합은 아닌거 같다.
  • 따라서 내가 생각하기엔 클래스가 많은 책임을 갖는다면 많은 문제점이 발생할 수 있는 것은 맞지만 이게 강한 결합과 같은 의미인거는 아닌 것 같다.
  • 책에서도 많은 책임 = 강한 결합이 아니라 많은 책임을 가지면 강한 결합이 잘 일어나고, 단일 책임 원칙을 지켜 설계를 하면 강한 결합을 많이 없앨 수 있다고 말하는 것 같다.

results matching ""

    No results matching ""